// Fill out your copyright notice in the Description page of Project Settings.

#include "SimpleCharacter.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/Controller.h"
#include "SimpleMovementComponent.h"
#include "SimpleWeapon.h"
#include "Net/UnrealNetwork.h"
#include "HealthComponent.h"
#include "SimpleGameMode.h"
#include "Kismet/GameplayStatics.h"
#include "Sound/SoundCue.h"
#include "SimplePlayerController.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "AIController.h"


ASimpleCharacter::ASimpleCharacter(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer.SetDefaultSubobjectClass<USimpleMovementComponent>(ACharacter::CharacterMovementComponentName))
{
 	
	PrimaryActorTick.bCanEverTick = true;

	GetCapsuleComponent()->InitCapsuleSize(50.f, 50.f);
	GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);

	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;


	CameraBoom = ObjectInitializer.CreateDefaultSubobject<USpringArmComponent>(this,TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->bAbsoluteRotation = true; 
	CameraBoom->TargetArmLength = 1200.f;
	CameraBoom->RelativeRotation = FRotator(-80.f, 0.f, 0.f);
	CameraBoom->bDoCollisionTest = false; 

	CameraComponent = ObjectInitializer.CreateDefaultSubobject<UCameraComponent>(this,TEXT("CameraComponent"));
	CameraComponent->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
	CameraComponent->bUsePawnControlRotation = false;

	HealthComponent = ObjectInitializer.CreateDefaultSubobject<UHealthComponent>(this, TEXT("HealthComponent"));
	HealthComponent->OnHealthChanged.AddDynamic(this, &ASimpleCharacter::HandleOnHealthChanged);



	bWantsToFire = false;
	bIsDying = false;
	bReplicates = true;
	bReplicateMovement = true;
}


void ASimpleCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(ASimpleCharacter, CurrentWeapon);
	DOREPLIFETIME(ASimpleCharacter, ShootBy);
}

void ASimpleCharacter::PostInitializeComponents()
{
	Super::PostInitializeComponents();
	if (Role == ROLE_Authority)
	{
		SpawnDefaultWeapon();
		//UKismetMathLibrary::RandomInteger()
		//UE_LOG(LogClass, Warning, TEXT("PostInitializeComponents"));
	}
}


void ASimpleCharacter::Die(class APawn* InstigatedBy, AActor* DamageCauser)
{
	if (bIsDying
		||IsPendingKill()
		||Role!=ROLE_Authority
		||GetWorld()->GetAuthGameMode<ASimpleGameMode>()==NULL)
	{
		return;
	}
	
	AAIController* AIController = Cast<AAIController>(InstigatedBy->GetController());
	if (!AIController)
	{
		AController* const KilledPlayer = (Controller != NULL) ? Controller : Cast<AController>(GetOwner());
		GetWorld()->GetAuthGameMode<ASimpleGameMode>()->Killed(InstigatedBy->GetController(), KilledPlayer);
	}

	if (HasAuthority())
	{
		OnDeadBlueprintEvent();
	}

	NetUpdateFrequency = GetDefault<ASimpleCharacter>()->NetUpdateFrequency;
	GetCharacterMovement()->ForceReplicationUpdate();


	OnDeath();
}

void ASimpleCharacter::BeginPlay()
{
	Super::BeginPlay();
	RandomPlayerColor();
}


void ASimpleCharacter::SpawnDefaultWeapon()
{
	if (Role < ROLE_Authority) return;
	if (DefaultWeapon)
	{
		FActorSpawnParameters SpawnInfo;
		SpawnInfo.Owner = this;
		SpawnInfo.Instigator = this;
		SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
		ASimpleWeapon* SimpleWeapon = GetWorld()->SpawnActor<ASimpleWeapon>(DefaultWeapon,SpawnInfo);
		CurrentWeapon = SimpleWeapon ? SimpleWeapon : NULL;
		if (CurrentWeapon)
		{
			CurrentWeapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, TEXT("WeaponSocket"));
			//UE_LOG(LogClass, Warning, TEXT("SpawnDefaultWeapon Succ"));
		}
	}
	
}

void ASimpleCharacter::OnStartFire()
{
	
	if (Controller != NULL)
	{
		//UE_LOG(LogClass, Warning, TEXT("OnStartFire"));
		StartWeaponFire();
	}
}

void ASimpleCharacter::OnStopFire()
{
	StopWeaponFire();
}

void ASimpleCharacter::StartWeaponFire()
{
	if (!bWantsToFire)
	{
		bWantsToFire = true;
		if (CurrentWeapon)
		{
			CurrentWeapon->StartFire();
		//	UE_LOG(LogClass, Warning, TEXT("StartWeaponFire"));
		}
	}
}

void ASimpleCharacter::StopWeaponFire()
{
	if (bWantsToFire)
	{
		bWantsToFire = false;
		if (CurrentWeapon)
		{
			CurrentWeapon->StopFire();
		}
	}
}

void ASimpleCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}


void ASimpleCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ASimpleCharacter::OnStartFire);
	PlayerInputComponent->BindAction("Fire", IE_Released, this, &ASimpleCharacter::OnStopFire);
	PlayerInputComponent->BindAxis("MoveForward", this, &ASimpleCharacter::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &ASimpleCharacter::MoveRight);
}

void ASimpleCharacter::UpdatePlayerMaterials_Implementation(UMaterialInterface* Material)
{
	GetMesh()->SetMaterial(0,Material);
}

void ASimpleCharacter::MoveForward(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, Value);
	}
}

void ASimpleCharacter::MoveRight(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		AddMovementInput(Direction, Value);
	}
}

void ASimpleCharacter::HandleOnHealthChanged(UHealthComponent* HealthComponent, float Health, float Damage,
		const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser)
{
	APawn* InstigatedByPawn = InstigatedBy->GetPawn();


	if (InstigatedByPawn)
	{
		ShootBy = InstigatedByPawn;
	}

	if (DamageCauser)
	{
		DamageCa = DamageCauser;
	}

	if (Health <= 0)
	{
		Die(ShootBy.Get(), DamageCa.Get());
	}
}

void ASimpleCharacter::RandomPlayerColor()
{
	UMaterialInstanceDynamic* PlayerMaterialIf;
	if (GetMesh()->GetMaterial(0))
	{
		PlayerMaterialIf = GetMesh()->CreateDynamicMaterialInstance(0, GetMesh()->GetMaterial(0));
		UMaterialInterface* Material = Cast<UMaterialInterface>(PlayerMaterialIf);
		GetMesh()->SetMaterial(0, Material);
		FLinearColor PlayerColor;
		PlayerColor.A = 1.0f;
		PlayerColor.B = FMath::FRandRange(0.f, 1.0f);
		PlayerColor.R = FMath::FRandRange(0.f, 1.0f);
		PlayerColor.G = FMath::FRandRange(0.f, 1.0f);
		PlayerMaterialIf->SetVectorParameterValue(TEXT("PlayerColor"), PlayerColor);
	}
}

void ASimpleCharacter::OnDeath()
{
	if (bIsDying) return;
	
	bIsDying = true;
	bReplicateMovement = false;


	ASimplePlayerController* SimplePlayerController = Cast<ASimplePlayerController>(Controller);

	if (SimplePlayerController)
	{
		SimplePlayerController->OnDeadImplementableEvent();
	}

	SetActorEnableCollision(true);
	DetachFromControllerPendingDestroy();
	
	if (HasAuthority())
	{
		if (DieMaterial)
		{
			UpdatePlayerMaterials(DieMaterial);
		}
		CurrentWeapon->SetLifeSpan(3.f);
		SetLifeSpan(3.f);
	}
}
